package org.zsk.cs.sendmail;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.zsk.cs.dao.UserDao;
import org.zsk.cs.domain.po.User;
import org.zsk.cs.exception.BizException;
import org.zsk.cs.util.UserUtils;
import org.zsk.cs.util.VerifyCode;
import org.zsk.cs.util.common.AppConstants;
import org.zsk.cs.util.common.enums.EmailSubject;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.time.Duration;

/**
 * <p>
 *     邮件 serviceImpl
 * </p>
 *
 * @author zsk
 * @version 1.0
 * Created on 2020/4/19
 */
@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
public class MailServiceImpl implements MailService {

    private final UserDao userDao;
    private final JavaMailSender javaMailSender;
    private final TemplateEngine templateEngine;
    private final RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    public MailServiceImpl(UserDao userDao, JavaMailSender javaMailSender, TemplateEngine templateEngine, RedisTemplate redisTemplate) {
        this.userDao = userDao;
        this.javaMailSender = javaMailSender;
        this.templateEngine = templateEngine;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void sendMailWithImg(String from, String to,
                                String subject, String content,
                                String[] srcPath, String[] resIds) throws MessagingException {
        if (srcPath.length != resIds.length) {
            log.info("发送带图片邮件失败");
            throw new BizException("图片资源不存在");
        }
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper =
                new MimeMessageHelper(message,true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content,true);
        for (int i = 0; i < srcPath.length; i++) {
            FileSystemResource res =
                    new FileSystemResource(new File(srcPath[i]));
            helper.addInline(resIds[i], res);
        }
        javaMailSender.send(message);
        log.info("发送带图片邮件成功");
    }

    @Override
    public void sendSimpleMail(String from, String to, String cc, String subject, String content) {
        SimpleMailMessage simpMsg = new SimpleMailMessage();
        simpMsg.setFrom(from);
        simpMsg.setTo(to);
        simpMsg.setCc(cc);
        simpMsg.setSubject(subject);
        simpMsg.setText(content);
        javaMailSender.send(simpMsg);
        log.info("发送普通邮件成功");
    }

    @Override
    public void sendAttachFileMail(String from, String to,
                                   String subject, String content, File file) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message,true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(content);
        helper.addAttachment(file.getName(), file);
        javaMailSender.send(message);
        log.info("发送附件邮件成功");
    }

    @Override
    public void sendHtmlMail(String from, String to,
                             String subject, String content) throws MessagingException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, true);
        helper.setTo(to);
        helper.setFrom(from);
        helper.setSubject(subject);
        helper.setText(content, true);
        javaMailSender.send(message);
        log.info("发送html邮件成功");
    }

    @Override
    public synchronized boolean bind(String email, String emailVerifyCode) {
        //验证码验证
        if (!emailVerifyCode.equals(redisTemplate.opsForValue()
                .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()))){
            log.debug("正确验证码: "+redisTemplate.opsForValue()
                    .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()));
            throw new BizException("邮箱验证码错误");
        }
        //验证邮箱
        if (userDao.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail,email))!=null){
            log.debug("邮箱已被绑定："+email);
            throw new BizException("邮箱已被绑定");
        }

        User user=userDao.selectById(UserUtils.getCurrentUser().getId());
        user.setEmail(email);
        user.setEmailActive(true);
        return userDao.updateById(user)==1;
    }

    @Override
    public boolean active(String emailVerifyCode){
        //验证码验证
        if (!emailVerifyCode.equals(redisTemplate.opsForValue()
                .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()))){
            log.debug("正确验证码: "+redisTemplate.opsForValue()
                    .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()));
            throw new BizException("邮箱验证码错误");
        }

        User user=new User();
        user.setId(UserUtils.getCurrentUser().getId());
        user.setEmailActive(true);
        return userDao.updateById(user)==1;
    }

    @Override
    public boolean unBind(String emailVerifyCode) {
        //验证码验证
        if (!emailVerifyCode.equals(redisTemplate.opsForValue()
                .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()))){
            log.debug("正确验证码: "+redisTemplate.opsForValue()
                    .get(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()));
            throw new BizException("邮箱验证码错误");
        }

        return userDao.update(null,new LambdaUpdateWrapper<User>()
                .set(User::getEmail,null)
                .set(User::getEmailActive,false)
                .eq(User::getId,UserUtils.getCurrentUser().getId()))==1;
    }

    @Override
    public boolean sendEmailVerifyCode(EmailSubject emailSubject,String email) throws MessagingException {
        User user;
        //获取验证码
        String emailVerifyCode=VerifyCode.getInstance().createVerifyCode();
        //存入redis中
        switch (emailSubject){
            case BIND:
            case UNBIND:
                redisTemplate.opsForValue()
                        .set(AppConstants.EMAIL_VERIFY_CODE_PREFIX+UserUtils.getCurrentUser().getId()
                                ,emailVerifyCode, Duration.ofSeconds(60));
                user=userDao.selectById(UserUtils.getCurrentUser().getId());
                break;
            case RESETPASSWORD:
                redisTemplate.opsForValue()
                        .set(AppConstants.EMAIL_VERIFY_CODE_PREFIX+email
                                ,emailVerifyCode, Duration.ofSeconds(60));
                user=userDao.selectOne(new LambdaQueryWrapper<User>().eq(User::getEmail,email));
                break;
            default:
                log.debug("非法邮箱验证码类型");
                throw new BizException("非法邮箱验证码类型");
        }

        //发送激活邮件
        Context ctx = new Context();
        ctx.setVariable("username", user.getUsername());
        String curEmail="";
        //绑定
        if (StringUtils.hasText(email)){
            //绑定
            ctx.setVariable("email", email);
            curEmail=email;
        }else {
            //解绑
            ctx.setVariable("email", user.getEmail());
            curEmail=user.getEmail();
        }
        ctx.setVariable("emailVerifyCode",emailVerifyCode);
        //邮箱主题
        ctx.setVariable("subject",emailSubject.getDesc());
        //邮件模板
        String mail = templateEngine.process(AppConstants.BIND_MAIL_TEMPLATE, ctx);
        //发送邮件
        sendHtmlMail(AppConstants.MAIL_FROMER,
                curEmail,
                emailSubject.getDesc()+"邮箱",
                mail);

        return true;
    }
}
